package com.itwxz.games.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.itwxz.common.core.domain.R;
import com.itwxz.common.core.redis.RedisCache;
import com.itwxz.common.exception.ServiceException;
import com.itwxz.common.utils.ServletUtils;
import com.itwxz.common.utils.bean.BeanUtils;
import com.itwxz.common.utils.ip.IpUtils;
import com.itwxz.games.domain.undercover.UCreateRoomInfo;
import com.itwxz.games.domain.undercover.UIdentity;
import com.itwxz.games.domain.undercover.URoom;
import com.itwxz.games.domain.undercover.UndercoverWord;
import com.itwxz.games.service.UndercoverService;
import com.itwxz.games.utils.CreateIdUtils;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@RequiredArgsConstructor
public class UndercoverServiceImpl implements UndercoverService {
    private final CreateIdUtils cIdUtils;
    private final RedisCache redisCache;

    @Override
    public UndercoverWord getWords() {
        try {
            // 调用远程接口
            HttpResponse response = HttpRequest.get("http://zhuoyouwx.afunapp.com/game/ajax_words")
                    .timeout(5000)
                    .execute();

            if (response.isOk()) {
                String body = response.body();
                JSONObject json = JSONUtil.parseObj(body);
                log.info("获取词条成功: {}", json);

                // 解析成 UndercoverWord

                return UndercoverWord.builder()
                        .civilian(json.getStr("pingmin"))   // 平民词
                        .undercover(json.getStr("wodi"))   // 卧底词
                        .build();
            } else {
                log.error("请求失败，状态码: {}", response.getStatus());
                throw new ServiceException("获取失败请重新尝试");
            }
        } catch (Exception e) {
            log.error("获取词条异常", e);
            throw new ServiceException("获取失败请重新尝试");
        }
    }

    @Override
    public URoom createRoom(UCreateRoomInfo info) {
        URoom r = BeanUtils.copyBean(info, URoom.class);
        r.setRoomId(cIdUtils.getUCRoomId());

        List<UIdentity> players = new ArrayList<>();
        List<UIdentity> undercoverPlayers = new ArrayList<>();

        int total = r.getTotalPeoples();
        int undercoverCount = r.getUndercover();

        for (int i = 0; i < total; i++) {
            // 前 undercoverCount 个是卧底
            boolean isUndercover = i < undercoverCount;
            UIdentity identity = UIdentity.builder()
                    .roomId(r.getRoomId())
                    .word(isUndercover ? r.getUndercoverWord() : r.getCivilianWord())
                    .isMensch(!isUndercover)
                    .isHomeOwner(false)
                    .joined(false)
                    .build();
            players.add(identity);
        }

        Collections.shuffle(players);

        int index = 1;
        for (UIdentity player : players) {
            player.setId(index++);
            if (!player.getIsMensch()) undercoverPlayers.add(player);
        }

        r.setPlayers(players);
        r.setUndercoverPlayers(undercoverPlayers);

        // 这里可以把 r 存到 Redis
        redisCache.setCacheObject(
                cIdUtils.getUKeyPrefix() + r.getRoomId(),
                r, 2, TimeUnit.HOURS
        );
        log.info(r.toString());

        return r;
    }


    @Override
    public UIdentity joinRoom(String roomId) {
        String key = cIdUtils.getUKeyPrefix() + roomId;
        String lockKey = "lock:undercover:room:" + roomId; // 每个房间独立的锁键

        // 尝试加锁，最多等待 5 秒
        if (!redisCache.tryLock(lockKey, 5, TimeUnit.SECONDS))
            return UIdentity.builder()
                    .id(0)
                    .build();

        try {
            URoom URoom = redisCache.getCacheObject(key);
            if (URoom == null)
                throw new ServiceException("房间不存在或已过期");


            // 原地打乱，随机分配身份
            Collections.shuffle(URoom.getPlayers());

            // 找出第一个未加入的身份
            UIdentity available = URoom.getPlayers().stream()
                    .filter(p -> p.getJoined() == null || !p.getJoined())
                    .findFirst()
                    .orElse(null);

            if (available == null)
                throw new ServiceException("房间已满");

            // 分配身份
            available.setJoined(true);
            available.setIp(IpUtils.getIpAddr());
            available.setTotalPeoples(URoom.getTotalPeoples());

            final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
            available.setBrowser(userAgent.getBrowser().getName());
            available.setOs(userAgent.getOperatingSystem().getName());

            // 更新 Redis 中的房间信息
            redisCache.setCacheObject(key, URoom, 2, TimeUnit.HOURS);

            return available;
        } finally {
            // 确保锁一定被释放
            redisCache.unlock(lockKey);
        }
    }

    @Override
    public UIdentity createRoomNoOwner(UCreateRoomInfo info) {
        // 获取关键词
        UndercoverWord words = getWords();

        // 给词赋值
        info.setUndercoverWord(words.getUndercover());
        info.setCivilianWord(words.getCivilian());

        // 创建房间
        URoom room = createRoom(info);

        // 分发身份
        UIdentity identity = joinRoom(String.valueOf(room.getRoomId()));
        identity.setIsHomeOwner(true);

        return identity;
    }

    @Override
    public R<Boolean> checkRoom(String roomId) {
        if (roomId == null || roomId.trim().isEmpty()) {
            return R.ok(false);
        }

        String key = cIdUtils.getUKeyPrefix() + roomId.trim();
        URoom uRoom = redisCache.getCacheObject(key);

        if (uRoom == null) {
            return R.ok(false);
        }

        return R.ok(true);
    }

    @Override
    public R<Boolean> checkRoomAndId(String roomId, String id) {
        if (roomId == null || roomId.trim().isEmpty()) {
            return R.ok(false);
        }

        String key = cIdUtils.getUKeyPrefix() + roomId.trim();
        URoom uRoom = redisCache.getCacheObject(key);

        if (uRoom == null)
            throw new ServiceException("房间不存在");

        Integer uid = Integer.valueOf(id);
        for (UIdentity player : uRoom.getPlayers()) {
            if (player.getId().equals(uid) && !player.getIsMensch()) {
                return R.ok(false);
            }
        }

        return R.ok(true);
    }

    @Override
    public R<Boolean> closeRoom(String roomId) {
        String key = cIdUtils.getUKeyPrefix() + roomId;
        if (redisCache.deleteObject(key)) {
            log.info("房间 {} 已关闭", roomId);
        }
        return R.ok(true);
    }

}
